
#include "output.h"
#include <libgen.h>

const char * POLICY[] = {"NOLM","FI","PF","FA","FT","PV","ALLLM","PFD","WKS","CACHE","L1CACHE","L2CACHE"};

uint32_t
fileSize(std::string fileName)
{
    uint32_t  l,m;
    ifstream file;
    file.open(fileName.c_str(), ifstream::in);
    l = file.tellg();
    file.seekg (0, ios::end);
    m = file.tellg();
    file.close();
    return (m-l);
}

void
outputSimulationDescription(ConfigParameter conf)
{
    for (int i=0;i<conf.getNumberApps();i++) {
         std::cout <<"Memory Tellme : Dirname : " <<conf.getDirname(i)<<
                     " threads: " <<conf.getThreads(i)<<std::endl;
    }
    std::cout <<"Total Threads: "<<conf.getTotalThreads()<<" option:"<<conf.getOption()<<std::endl;
    std::cout <<"Chips: "<<conf.getNumberChips()<<std::endl;

}


std::string
createFileName(char * dirname,Memory * mem,const char * pre,uint32_t policy,uint32_t threshold,bool skipwrite)
{
    std::ofstream outfile;
    std::string outputFilename;
    std::string tmp(dirname);
    std::string headerFileName(pre);
    std::string app;
    std::string params;

    /* simulations params*/
    stringstream st;
    st << mem->getPagesize();
    params += "-p:" + st.str();
    st.str( "" );
    st << mem->getLMSize();
    params += "-LM:" + st.str();
    st.str( "" );
    st << POLICY[policy];
    params += "-P:" + st.str();
    st << threshold;
    params += "-TH:" + st.str();
    st.str( "" );
    st << mem->getMigrate();
    params += "-M:" + st.str();

    if (skipwrite) {
        params += "-RDONLY";
    }

    size_t found =tmp.find_last_of("/");
    if (found!=string::npos) {
        app=tmp.substr(found+1);
    }
    outputFilename = headerFileName + app + params + ".txt";

    return outputFilename;
}


void
outputResults(LocalPartitionCMP *CMP,char * dirname,Memory * mem,uint32_t policy,uint32_t threshold,
        bool skipwrite)
{
/*
    std::ofstream outfile;
    std::string outputFilename;

    outputFilename = createFileName(dirname,mem,"Tellme-", policy,threshold, skipwrite);
    outfile.open (outputFilename.c_str(), ios::trunc|ios::out|ios::trunc);
    //outfile << "THREAD,POLICY,THRESHOLD,MM,LM,RLM,TOTAL_ACCESSES,TOTAL_PAGES,MIGRATIONS"<<std::endl;
    for (int tid=0;tid<mem->getNumThreads();tid++) {
        outfile << tid << "," <<POLICY[policy]<<","<<threshold;
        uint64_t total=0;
        uint32_t L0Hits=0,L0Misses=0;
        outfile << tid << ","<< threshold;
        if (CMP->getL0Size()>0) {
            L0Hits=CMP->getL0CacheHits(tid);
            L0Misses=CMP->getL0CacheMisses(tid);
            total+=L0Hits;
        }
        total+=CMP->getLPHits(tid)+CMP->getRemoteLPHits(tid);
        total+=CMP->getMainMemorAccesses(tid);
        outfile <<total<<","<<L0Hits<<","<<L0Misses<<",";
        outfile <<CMP->getLPHits(tid)<<","<<CMP->getRemoteLPHits(tid)<<",";
        outfile <<CMP->getMainMemorAccesses(tid);
        uint32_t replace = CMP->LPReplacements[tid];
        uint32_t tlbhits = CMP->getTlbHits(tid);
        uint32_t tlbmisses = CMP->getTlbMisses(tid);
        outfile <<","<<replace<<","<<tlbhits<<","<<tlbmisses<<std::endl;
        outfile << "," << total <<"," <<mem->getNumPages(thread) <<","<<mem->getMigrations(thread)<<std::endl;
    }
    outfile.close();
    */
}

void
outputMigrationResults(char * dirname,Memory * mem,uint32_t policy,uint32_t threshold,bool skipwrite)
{
    std::ofstream outfile;
    std::string outputFilename;

    outputFilename = createFileName(dirname,mem,"Migrate-", policy,threshold, skipwrite);
    outfile.open (outputFilename.c_str(), ios::out|ios::trunc);
    for (int thread=0;thread<mem->getNumThreads();thread++) {
        std::vector<pair_value> success = mem->getMigrationSuccess(thread);
        uint32_t i=0;
        for (std::vector<pair_value>::const_iterator itr = success.begin(); itr != success.end(); itr++) {
            outfile << thread << "," <<(threshold*i) << "," <<itr->first<<","<<itr->second << std::endl;
            i++;
        }
    }
    outfile.close();
}


/*Dump Working set to file */
void
outputWorkingSet(char * dirname,Memory * mem,uint32_t access)
{
    std::ofstream outfile;
    std::string outputFilename;

    std::string sdirname(dirname);
    std::string app;
    std::string params;

    stringstream st;
    st << mem->getPagesize();
    params += "-p:" + st.str();
    if (access>0) {
        st.str( "" );
        st << access;
        params += "-step:" + st.str();
    }

    size_t found =sdirname.find_last_of("/");
    if (found!=string::npos) {
        app=sdirname.substr(found+1);
    }

    outputFilename =  "WorkingSet-" + app + params + ".txt";
    std::cout   << "Creating :" << outputFilename << std::endl;
    outfile.open (outputFilename.c_str(), ios::out|ios::trunc);
    //LM RLM MM
    outfile << "#PAGE_NUMBER, ADRESSES, ACCESSES"<<std::endl;
    mem->dumpPageTable(outfile);
    outfile.close();
}

void
outputLPResults(Memory * mem,Trace * trace,uint32_t level,uint32_t *LPHits)
{
    std::ofstream outfile;
    std::string outputFilename;
    char dirname[1024];
    trace->getDirname(dirname);

    std::string sdirname(dirname);
    std::string app;
    std::string params;

    stringstream st;
    st << mem->getPagesize();
    params += "-p:" + st.str();
    st.str( "" );
    st << mem->getLMSize();
    params += "-C:" + st.str();


    size_t found =sdirname.find_last_of("/");
    if (found!=string::npos) {
        app=sdirname.substr(found+1);
    }
    if (level==1) {
        outputFilename =  "CacheRatio-" + app + params + ".txt";
    }
    else {
        outputFilename =  "CacheRatioL2-" + app + params + ".txt";
    }
    std::cout   << "Creating :" << outputFilename << std::endl;
    outfile.open (outputFilename.c_str(), ios::out|ios::trunc);
    float result=0;
    for(uint32_t tid=0;tid<mem->getNumThreads();tid++) {
         result = ((float) LPHits[tid] / (float)trace->getAccessSize(tid))*100;
         outfile << tid << "," << result<<std::endl;
    }
    outfile.close();
}

void
outputThresholdLMResults (LocalPartitionCMP * CMP,Memory * mem,Trace * trace,
        ConfigParameter conf)
{
    std::ofstream outfile;
    std::string outputFilename;
    char dirname[1024];
    trace->getDirname(dirname);

    std::string sdirname(dirname);
    std::string app;

    stringstream params;
    params<<"-L:"<<CMP->getLineSize()<<"-L0:"<< CMP->getL0Size()<<
         "-L0I:"<< CMP->getL0InvalidatePolicy()<< "-p:"<<conf.getPageSize()<<
         "-VP:"<<CMP->getVictimPolicy()<<"-C:"<<mem->getLMSize()<<
         "-th:"<<conf.getThreshold()<<"-chips:"<<conf.getNumberChips()<<
         "-MULTIFELI:"<<conf.getMultiFELIPolicy()<<"-ChipTh:"<<conf.getInterChipThreshold();

    size_t found =sdirname.find_last_of("/");
    if (found!=string::npos) {
        app=sdirname.substr(found+1);
    }
    outputFilename =  "LPResults-" + app + params.str() + ".txt";
    std::cout   << "Creating :" << outputFilename << std::endl;
    outfile.open (outputFilename.c_str(), ios::app);
    outfile <<"threadID,migrationThreshold,totalAccesses,L0Hits,L0Misses,"
              "LPHits,LPRemoteHitsOnChip,LPRemoteHitsOffChip,MainMemoryAccesses,"
              "pageMigrationsOnChip,pageMigrationsOffChip,TLBHits,TLBMisses"<<std::endl;
    for(uint32_t tid=0;tid<mem->getNumThreads();tid++) {
        uint64_t total=0;
        uint32_t L0Hits=0,L0Misses=0;
        outfile << tid << ","<< conf.getThreshold() <<",";
        if (CMP->getL0Size()>0) {
            L0Hits=CMP->getL0CacheHits(tid);
            L0Misses=CMP->getL0CacheMisses(tid);
            total+=L0Hits;
        }
        total+=CMP->getLPHits(tid)+CMP->getLPRemoteHitsOnChip(tid)+CMP->getLPRemoteHitsOffChip(tid);
        total+=CMP->getMainMemoryAccesses(tid);
        outfile <<total<<","<<L0Hits<<","<<L0Misses<<",";
        outfile <<CMP->getLPHits(tid)<<","<<CMP->getLPRemoteHitsOnChip(tid)<<
                ","<<CMP->getLPRemoteHitsOffChip(tid)<<","<<CMP->getMainMemoryAccesses(tid)<<",";
        outfile <<CMP->getLPReplacementsOnChip(tid)<<","<<CMP->getLPReplacementsOffChip(tid)<<",";
        outfile << CMP->getTlbHits(tid)<<","<<CMP->getTlbMisses(tid)<<std::endl;
    }
    outfile.close();
    /*
    outputFilename =  "PageTableMap-" + app + params + ".txt";
    outfile.open (outputFilename.c_str(), ios::app);
    mem->dumpExtendedPageTable(outfile,threshold);
    outfile.close();
    */
}



void
printLMstatus(Memory *mem,Trace *trace,uint32_t policy)
{
    std::cout   << "Policy:" <<POLICY[policy] <<std::endl;
    for(uint32_t tid=0;tid<mem->getNumThreads();tid++) {
        for (uint32_t index=0;index<mem->getLMSize();index++) {
            uint32_t page=trace->getMaxAccessPage(tid,index);
            std::cout << "Thread:"<<tid<<":Page:0x"<< std::hex <<page <<":"<<
                "location:"<< std::dec << mem->getLocation(page)<<":access:"<<trace->getAccess(tid,page)<<std::endl;
        }
    }
}


void
outputCMPResults (Memory * mem,Trace * trace,CacheCMP * cacheCMP,
                  ConfigParameter & conf)
{
    std::ofstream outfile;
    std::string outputFilename;
    char dirname[1024];
    trace->getDirname(dirname);

    std::string sdirname(dirname);
    std::string app;
    stringstream params;
    params<<"-L:"<<cacheCMP->getLineSize()<<"-L0:"<< cacheCMP->getL0Size()<<
         "-L1:"<< cacheCMP->getL1Size()<< "-L2:"<<cacheCMP->getL2Size()<<
         "-chips:"<<conf.getNumberChips();

    size_t found =sdirname.find_last_of("/");
    if (found!=string::npos) {
        app=sdirname.substr(found+1);
    }

    outputFilename =  "CMPCacheResults-" + app + params.str() + ".txt";
    std::cout   << "Creating :" << outputFilename << std::endl;
    outfile.open (outputFilename.c_str(), ios::app);
    outfile <<"threadID,total,L0Hits,L0Misses,L1Hits,L1Misses,"
        "L1Invalidates,L2Hits,L2Misses,L2HitInvalidates,L2CacheRemoteAccesses,"
        "L2RemoteHitsOnChip,L2RemoteHitsOffChip,MainMemoryAccesses,TLBHits,TLBMisses"<<std::endl;
    for(uint32_t tid=0;tid<mem->getNumThreads();tid++) {
        uint64_t total=0;
        if (cacheCMP->getL0Size()>0)
            total+=cacheCMP->getL0CacheHits(tid);
        if (cacheCMP->getL1Size()>0)
              total+=cacheCMP->getL1CacheHits(tid);
        if (cacheCMP->getL2Size()>0)
              total+=cacheCMP->getL2CacheHits(tid) +
                     cacheCMP->getL2CacheRemoteHitsOnChip(tid)+
                     cacheCMP->getL2CacheRemoteHitsOffChip(tid);
        total+=cacheCMP->getMainMemoryAccesses(tid);

        outfile << tid << ","<<total<<",";
        if (cacheCMP->getL0Size()>0) {
            outfile <<cacheCMP->getL0CacheHits(tid)<<","
                    <<cacheCMP->getL0CacheMisses(tid)<<",";
        }
        else {
            outfile<<"0,0,";
        }
        if (cacheCMP->getL1Size()>0) {
            outfile <<cacheCMP->getL1CacheHits(tid)<<","
                    <<cacheCMP->getL1CacheMisses(tid)<<","
                    <<cacheCMP->getL1CacheHitInvalidate(tid)<<",";
        }
        else {
            outfile<<"0,0,0,";
        }

        if (cacheCMP->getL2Size()>0) {
            outfile <<cacheCMP->getL2CacheHits(tid)<<","
                    <<cacheCMP->getL2CacheMisses(tid)<<","
                    <<cacheCMP->getL2CacheHitInvalidate(tid)<<","
                    <<cacheCMP->getL2CacheRemoteAccesses(tid)<<","
                    <<cacheCMP->getL2CacheRemoteHitsOnChip(tid)<<","
                    <<cacheCMP->getL2CacheRemoteHitsOffChip(tid)<<",";
        }
        else {
            outfile<<"0,0,0,0,0,";
        }
        outfile << cacheCMP->getMainMemoryAccesses(tid)<<","
                << cacheCMP->getTlbHits(tid)<<","
                << cacheCMP->getTlbMisses(tid)<<std::endl;
    }
    outfile.close();
}

void
outputTLBResults (const char *dirname,TLBCMP * CMP)
{
    std::ofstream outfile;
    std::string outputFilename;
    std::string sdirname(dirname);
    std::string app;
    std::string params;

    stringstream st;
    uint32_t lineSize=CMP->getLineSize();
    st << lineSize;
    params += "-L:" + st.str();
    st.str( "" );
    st << CMP->getTLB1Size();
    params += "-TLB1:" + st.str();
    st.str( "" );
    st << CMP->getTLB1Nways();
    params += "-TLB1Ass:" + st.str();
    st.str( "" );
    st << CMP->getTLB2Size();
    params += "-TLB2:" + st.str();
    st.str( "" );
    st << CMP->getTLB2Nways();
    params += "-TLB2Ass:" + st.str();
    st.str( "" );
    st << CMP->getPagesInRange();
    params += "-PagesInRange:" + st.str();

    size_t found =sdirname.find_last_of("/");
    if (found!=string::npos) {
        app=sdirname.substr(found+1);
    }
    outputFilename =  "TLBResults-" + app + params + ".txt";
    std::cout   << "Creating :" << outputFilename << std::endl;
    outfile.open (outputFilename.c_str(), ios::out|ios::trunc);
    std::cout << "Output puts "<< CMP->getThreads()<< " Threads"<<std::endl;
    outfile <<"#thread,app,TLB1Hits,TLB1Misses,TLB1Eviction,TLB1ForcedEvictions,TLB1Accesses,TLB2Accesses,TLB2Eviction"<<std::endl;
    for(uint32_t tid=0;tid<CMP->getThreads();tid++) {
        outfile << tid << ",";
        char appname[1024],*bench;
        CMP->getAppName(appname,tid);
        bench=basename(appname);
        outfile<<bench<<",";
        outfile<<(100*(float)CMP->getTLB1Hits(tid)/(float)CMP->getTLB1Accesses(tid))<<",";
        outfile<<(100*(float)CMP->getTLB1Misses(tid)/(float)CMP->getTLB1Accesses(tid))<<",";
        outfile<<(100*(float)CMP->getTLB1EvictedPages(tid)/(float)CMP->getTLB1Accesses(tid))<<",";
        outfile<<(100*(float)CMP->getTLB1ForcedEvictedPages(tid)/(float)CMP->getTLB1Accesses(tid))<<",";
        outfile<<CMP->getTLB1Accesses(tid)<<",";
        if (CMP->getTLB2Size()>0)
            outfile<<CMP->getTLB2Accesses()<<","<<CMP->getTLB2EvictedPages()<<std::endl;
        else
            outfile<<"0,0"<<std::endl;
    }
    outfile.close();
}

void
outputTLBDirectory (Memory * mem,Trace * trace,TLBCMP * CMP)
{
    std::ofstream outfile;
    std::string outputFilename;
    char dirname[1024];
    trace->getDirname(dirname);

    std::string sdirname(dirname);
    std::string app;
    std::string params;

    stringstream st;
    uint32_t lineSize=CMP->getLineSize();
    st << lineSize;
    params += "-L:" + st.str();
    st.str( "" );
    st << CMP->getTLB1Size();
    params += "-TLB1:" + st.str();
    st.str( "" );
    st << CMP->getTLB1Nways();
    params += "-TLB1Ass:" + st.str();
    st.str( "" );
    st << CMP->getTLB2Size();
    params += "-TLB2:" + st.str();
    st.str( "" );
    st << CMP->getTLB2Nways();
    params += "-TLB2Ass:" + st.str();

    size_t found =sdirname.find_last_of("/");
    if (found!=string::npos) {
        app=sdirname.substr(found+1);
    }
    outputFilename =  "TLBDirectory-" + app + params + ".txt";
    std::cout   << "Creating :" << outputFilename << std::endl;
    outfile.open (outputFilename.c_str(), ios::app);

    outfile <<"#tid,TLB1Evictions,TLB2Evictions"<<std::endl;
    for(uint32_t tid=0;tid<mem->getNumThreads();tid++) {
        outfile << tid << ","<<CMP->getTLB1EvictedPages(tid);
        outfile << ","<<CMP->getTLB2EvictedPages()<<std::endl;
    }
    outfile.close();

}

void
outputL0 (Trace * trace,CacheCMP * CMP,uint32_t tid)
{
    std::ofstream outfile;
    std::string outputFilename;
    char dirname[1024];
    trace->getDirname(dirname);

    std::string sdirname(dirname);
    std::string app;
    std::string params;

    uint32_t lineSize=CMP->getLineSize();

    size_t found =sdirname.find_last_of("/");
    if (found!=string::npos) {
        app=sdirname.substr(found+1);
    }
    outputFilename =  "Cache-L0-" + app +  ".txt";
    std::cout   << "Creating :" << outputFilename << std::endl;
    outfile.open (outputFilename.c_str(), ios::app);

    uint32_t hits=CMP->getL0CacheHits(0);
    uint32_t misses=CMP->getL0CacheMisses(0);

    outfile << tid << ","<<lineSize<<","<<CMP->getL0Size()<<","<<((float)hits/(hits+misses))<<","<<((float)misses/(hits+misses))<<","<<hits+misses<<std::endl;
    outfile.close();

}

void outputSingleThreadCMPResults(Trace * trace,SingleThreadCMP * CMP)
{
    std::ofstream outfile;
    std::string outputFilename;
    char dirname[1024];
    trace->getDirname(dirname);

    std::string sdirname(dirname);
    std::string app;
    std::string params;

    stringstream st;
    uint32_t lineSize=CMP->getLineSize();
    st << lineSize;
    params += "-L:" + st.str();
    st.str( "" );
    st << CMP->getCacheSize();
    params += "-Cache:" + st.str();

    size_t found =sdirname.find_last_of("/");
    if (found!=string::npos) {
        app=sdirname.substr(found+1);
    }
    outputFilename =  "SimMethology-" + app + params + ".txt";
    std::cout   << "Creating :" << outputFilename << std::endl;
    outfile.open (outputFilename.c_str(), ios::app);

    uint32_t regions=CMP->getRegion();
    uint32_t tid=CMP->getThread();
    for (int i=0;i<regions;i++ ) {
        outfile << tid << ","<<i<<","<<CMP->getCacheHits(i)<<","<<CMP->getCacheMisses(i)<<std::endl;
    }
    outfile.close();

}
